package main

import (
	"cloudops/src/cache"
	"cloudops/src/common"
	"cloudops/src/config"
	"cloudops/src/cron"
	"cloudops/src/models"
	"cloudops/src/rpc"
	"cloudops/src/web"
	"context"
	"flag"
	"fmt"
	esl "github.com/ning1875/errgroup-signal/signal"
	"go.uber.org/zap"
)

func main() {
	// 主配置文件 命令行解析
	var (
		configFile string
	)

	flag.StringVar(&configFile, "f", "./server.yml", "config file")
	flag.Parse()

	// 加载主配置文件
	sc, err := config.LoadServer(configFile)
	if err != nil {
		fmt.Printf("Loading main configuration file failed： %v\n", err)
		return
	}
	fmt.Printf("Load main configuration file success： %v\n", sc)

	// 初始化日志
	logger := common.NewZaplogger(sc.LogLevel, sc.LogPath, sc.ErrLogPath)
	defer logger.Sync()
	sc.Logger = logger
	// 初始化数据库
	err = models.InitDb(sc)
	if err != nil {
		logger.Error("InitDb failed", zap.String("err", err.Error()))
		return
	}
	logger.Info("InitDb success")

	// 初始化casbin
	err = models.InitCasbin(sc)
	if err != nil {
		logger.Error("InitCasbin failed", zap.Error(err))
		return
	}
	logger.Info("InitCasbin success")

	err = models.MigrateTable()
	if err != nil {
		logger.Error("gorm-db同步表结构错误",

			zap.String("错误", err.Error()),
		)
		return
	}
	logger.Info("gorm-db同步表结构成功")

	// 同步表结构
	if sc.NeedMockData {
		logger.Info("配置开启mock数据，开始注入测试数据")
		// TODO 注入基础数据，最终要使用数据库表
		models.InsertBasicDbData(sc)
	} else {
		logger.Info("配置关闭mock数据，跳过注入测试数据")
	}

	// 初始化这个 cronManager
	cm := cron.NewCronManager(sc)

	// 初始化任务执行模块的cache
	tc := cache.NewTaskCache(sc)

	// 初始化服务树模块的cache
	streeC := cache.NewStreeCache(sc)

	// 初始化这个group
	// stopChan 有值，说明要退出
	// 首先添加一个退出信号管理
	group, stopChan := esl.SetupStopSignalContext()
	ctxAll, cancelAll := context.WithCancel(context.Background())

	// 启动定时任务
	group.Go(func() error {
		logger.Info("stopchan监听启动")
		for {
			select {
			case <-stopChan:
				logger.Info("捕获退出信号 停止ctx 通知所有任务退出")
				cancelAll()
				return nil
			}

		}
	})

	//  启动定时任务--同步公有云
	{
		if sc.PublicCloudSyncC.Enable {
			group.Go(func() error {

				logger.Info("计划任务--同步公有云--启动")
				err := cm.SyncCloudResourceManager(ctxAll)
				if err != nil {
					logger.Error("计划任务--同步公有云--报错", zap.Error(err))
				}
				return err
			})
		} else {
			logger.Info("计划任务--同步公有云--关闭")
		}

	}

	// 启动定时任务--服务树模块-缓存
	{
		if sc.StreeCacheC.Enable {
			// 在里面添加你的任务
			group.Go(func() error {

				logger.Info("计划任务--服务树模块-缓存启动")
				err := streeC.StreeCacheManager(ctxAll)
				if err != nil {
					logger.Error("计划任务--服务树模块--报错", zap.Error(err))
				}
				return err
			})
		} else {
			logger.Info("计划任务--服务树模块--关闭")
		}

	}

	// 工单自动处理模块
	{
		if sc.WorkOrderAutoActionC.Enable {
			// 在里面添加需要的任务
			group.Go(func() error {
				logger.Info("计划任务--工单通知模块--启动")
				err := cm.NotifyOrderManager(ctxAll)
				if err != nil {
					logger.Error("计划任务--工单通知模块--报错", zap.Error(err))
				}
				return err
			})
		} else {
			logger.Info("计划任务--工单通知模块--关闭")
		}
	}

	// 工单通知模块
	{
		if sc.WorkOrderAutoActionC.Enable {
			// 在里面添加你的任务
			group.Go(func() error {

				logger.Info("计划任务--工单通知模块--启动")
				err := cm.NotifyOrderManager(ctxAll)
				if err != nil {
					logger.Error("计划任务--工单通知模块--报错", zap.Error(err))
				}
				return err
			})
		} else {
			logger.Info("计划任务--工单通知模块--关闭")
		}
	}

	// 启动任务执行模块
	{
		if sc.JobExecC.Enable {
			group.Go(func() error {
				logger.Info("计划任务--任务执行模块启动")
				err := tc.TaskCacheManager(ctxAll)
				if err != nil {
					logger.Error("计划任务--任务执行模块报错", zap.Error(err))
				}
				return err
			})
		} else {
			logger.Info("计划任务--任务执行模块关闭")
		}
	}

	// 启动web服务
	group.Go(func() error {

		errChan := make(chan error, 1)
		go func() {
			errChan <- web.StartGIn(sc, streeC)
		}()

		logger.Info("web启动成功")
		select {
		case err := <-errChan:
			logger.Error("gin报错", zap.Error(err))
			return err
		case <-ctxAll.Done():
			logger.Info("gin收到其他任务退出信号 退出")
			return nil
		}
	})

	// 启动 GRPC 服务端
	group.Go(func() error {
		errChan := make(chan error, 1)
		go func() {
			errChan <- rpc.StartServerGrpc(sc, tc)
		}()
		select {
		case err := <-errChan:
			logger.Error("GRPC 发生错误", zap.Error(err))
			return err
		case <-errChan:
			logger.Info("收到退出信号 GRPC 退出")
		}
		return err
	})

	group.Wait()
}
